package com.free.semantic.core.service.impl;

import com.free.semantic.common.Ls;
import com.free.semantic.core.ConceptInstanceManage;
import com.free.semantic.core.ConceptManage;
import com.free.semantic.core.impl.ConceptInstanceManageImpl;
import com.free.semantic.core.impl.ConceptManageImpl;
import com.free.semantic.core.proxy.ProxyFunctionProvider;
import com.free.semantic.core.proxy.impl.ConceptInsManageProxy;
import com.free.semantic.core.script.SemanticNetEngine;
import com.free.semantic.core.script.impl.ScriptEngineImpl;
import com.free.semantic.core.service.ConceptGroupManage;
import com.free.semantic.core.takeclient.ConceptInsTakeCommand;
import com.free.semantic.core.takeclient.impl.LocalManageImpl;
import com.free.semantic.core.takeclient.impl.UrlClientImpl;
import com.free.semantic.req.RelationDefineGroup;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

import static com.free.semantic.core.concept.impl.ConceptSelfInfoConcept.FIND_MORE;
import static com.free.semantic.core.concept.impl.ConceptSelfInfoConcept.FIND_ONE;
import static com.free.semantic.utils.Utils.*;
import static com.free.semantic.utils.Utils.createRelation2;


public class ConceptGroupBaseManage implements ConceptGroupManage {

    private String baseUrl;

    private static final String THREE_FIND_ONE = "threeFindOne";

    private static final String TWO_FIND_ONE = "twoFindOne";

    private static final String MORE_FIND_ONE = "moreFindOne";

    Map<String, ConceptInstanceManage> manageMap = new LinkedHashMap<>();

    Map<String, String> conceptMangeURL = new HashMap<>();

    Map<String, Long> manageMapId = new LinkedHashMap<>();

    SemanticNetEngine scriptEngine = new ScriptEngineImpl();

    ConceptInstanceManage instanceManage;

    public ConceptGroupBaseManage(String baseUrl) {
        this.baseUrl = baseUrl;
        buildBaseManage();
    }


    @Override
    public ConceptInstanceManage getManage(String conceptName) {
        if (StringUtils.isBlank(conceptName)) {
            return instanceManage;
        } else {
            return manageMap.get(conceptName);
        }
    }

    @Override
    public void add(String modelName, ConceptInstanceManage modelInstance) {
        manageMap.put(modelName, modelInstance);
        String url = baseUrl + String.format("/manage/controller/%s/semantic", modelName);
        conceptMangeURL.put(modelName, url);
    }

    public void buildBaseManage() {
        RelationDefineGroup group = new RelationDefineGroup();

        defineRelation(group, TWO_FIND_ONE, defineItem(oneObj("A", "B"), moreObj("C")));

        defineRelation(group, THREE_FIND_ONE, defineItem(oneObj("A", "B", "C"), moreObj("D")));

        defineRelation(group, MORE_FIND_ONE, defineItem(moreObj("A"), oneObj("B")));

        ConceptManage model = getConceptManage(group);

        object(model, "@语义网络组", "语义网络组", "语义网络", "语义网络实现URL", "语义网络名称",
                "创建", "复制", "删除", "导入", "注册实现器", "语义网络脚本", "执行", "实现器", "实现器名称", "保存");

        createRelation(model, FIND_MORE, "语义网络组", "语义网络名称");
        createRelation2(model, TWO_FIND_ONE, "@语义网络组", "语义网络名称", "创建");
        createRelation2(model, FIND_ONE, "语义网络名称", "语义网络");
        createRelation2(model, FIND_ONE, "语义网络", "复制");
        createRelation2(model, FIND_ONE, "语义网络", "删除");
        createRelation2(model, FIND_ONE, "语义网络", "保存");
        createRelation2(model, FIND_ONE, "语义网络名称", "语义网络实现URL");

        createRelation2(model, THREE_FIND_ONE, "@语义网络组", "语义网络名称", "语义网络实现URL", "导入");
        createRelation2(model, THREE_FIND_ONE, "语义网络", "实现器", "实现器名称", "注册实现器");
        createRelation2(model, TWO_FIND_ONE, "语义网络名称", "语义网络脚本", "执行");

        instanceManage = new ConceptInstanceManageImpl(model);

        instanceManage.registerFunction(Ls.of("语义网络组"), "语义网络名称",
                context -> {
                    List<String> conceptNameList = new ArrayList<>(manageMap.keySet());
                    context.setValue("语义网络名称", conceptNameList);
                });

        instanceManage.registerFunction(Ls.of("@语义网络组", "语义网络名称"), "创建",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("已经存在名为%s的语义网络", name));
                    }
                    conceptMangeURL.put(name, baseUrl + String.format("/manage/controller/%s/semantic/", name));
                    ConceptManage conceptManage = new ConceptManageImpl();
                    ConceptInstanceManage ins = new ConceptInstanceManageImpl(conceptManage);
                    manageMap.put(name, ins);
                    context.setValue("创建", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络名称"), "语义网络",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    context.setValue("语义网络", name);
                });

        instanceManage.registerFunction(Ls.of("语义网络"), "复制",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    ConceptInstanceManage conceptInstanceManage = manageMap.get(name);
                    ConceptInsTakeCommand client = new LocalManageImpl(conceptInstanceManage);

                    SemanticNetEngine engine = new ScriptEngineImpl();
                    ConceptManage conceptManage = engine.buildManageFromTake(client);


                    ProxyFunctionProvider provider = new ProxyFunctionProvider(conceptManage, conceptInstanceManage);
                    provider.prepareFunctionMap();

                    ConceptInstanceManage ins = new ConceptInstanceManageImpl(conceptManage, provider);

                    manageMap.put(name + "副本", ins);
                    conceptMangeURL.put(name + "副本", baseUrl + String.format("/manage/controller/%s/semantic/", name + "副本"));
                    context.setValue("复制", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络"), "删除",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    manageMap.remove(name);
                    conceptMangeURL.remove(name);
                    context.setValue("删除", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络"), "保存",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    ConceptInstanceManage conceptInstanceManage = manageMap.get(name);





                    context.setValue("保存", "success");
                });


        instanceManage.registerFunction(Ls.of("语义网络名称"), "语义网络实现URL",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    String url = conceptMangeURL.get(name);
                    context.setValue("语义网络实现URL", url);
                });

        instanceManage.registerFunction(Ls.of("@语义网络组", "语义网络名称", "语义网络实现URL"), "导入",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("已经存在名为%s的语义网络", name));
                    }
                    String url = (String) context.getListValue("语义网络实现URL").get(0);
                    UrlClientImpl urlClient = new UrlClientImpl(url);
                    ConceptInsManageProxy proxy = new ConceptInsManageProxy(urlClient);
                    manageMap.put(name, proxy);
                    conceptMangeURL.put(name, baseUrl + String.format("/manage/controller/%s/semantic/", name));
                    context.setValue("导入", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络", "实现器", "实现器名称"), "注册实现器",
                context -> {
                    String name = (String) context.getListValue("语义网络").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    String url = (String) context.getListValue("实现器").get(0);
                    String providerName = (String) context.getListValue("实现器名称").get(0);
                    UrlClientImpl client = new UrlClientImpl(url);

                    ConceptInsManageProxy proxy = new ConceptInsManageProxy(client);
                    manageMap.get(name).registerFunction(providerName, relationItem ->
                            proxy.getFunction(relationItem.getSourceObjectList(), relationItem.getDestObject()));
                    context.setValue("注册实现器", "success");
                });

        instanceManage.registerFunction(Ls.of("语义网络名称", "语义网络脚本"), "执行",
                context -> {
                    String name = (String) context.getListValue("语义网络名称").get(0);
                    if (!manageMap.containsKey(name)) {
                        throw new RuntimeException(String.format("不存在名为%s的语义网络", name));
                    }
                    String script = (String) context.getListValue("语义网络脚本").get(0);
                    ConceptInstanceManage manage = manageMap.get(name);
                    Object object = scriptEngine.execScript(manage, script);
                    context.setValue("执行", object);
                });
    }


}
